package com.njchy.statistics.service.impl;

import com.google.common.collect.Lists;
import com.njchy.statistics.entity.RiverInfo;
import com.njchy.statistics.entity.dto.MatchIncomingPointsDTO;
import com.njchy.statistics.entity.dto.RiverSumDTO;
import com.njchy.statistics.entity.vo.RangeStatVO;
import com.njchy.statistics.mapper.AllMapper;
import com.njchy.statistics.service.AllServices;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
@Slf4j
@Service
@AllArgsConstructor
public class AllServiceImpl implements AllServices {

    private final AllMapper allMapper;
    private final ThreadPoolTaskExecutor taskExecutor;

    /**
     * 区间内面积和体积计算（返回值保留两位小数）
     */
    @Override
    public List<Map<String, String>> getAreaStatistic(String tableNameOne, String tableNameTwo) {
        // 1. 校验参数和查询数据（逻辑不变）
        validateParams(tableNameOne, tableNameTwo);
        List<Map<String, Object>> mapListOne = allMapper.queryTableData(tableNameOne);
        List<Map<String, Object>> mapListTwo = allMapper.queryTableData(tableNameTwo);
        validateData(mapListOne, tableNameOne);
        validateData(mapListTwo, tableNameTwo);

        // 2. 构建表二的fkid->value映射（逻辑不变）
        Map<String, BigDecimal> twoFkidValueMap = buildFkidValueMap(mapListTwo);

        // 3. 初始化区间统计容器（逻辑不变）
        Map<String, RangeStatVO> rangeStatMap = initRangeStatContainer();

        // 4. 遍历表一数据，过滤并统计有效数据（逻辑不变）
        for (Map<String, Object> oneMap : mapListOne) {
            try {
                String fkid = getFkid(oneMap);
                if (fkid == null || !twoFkidValueMap.containsKey(fkid)) {
                    continue;
                }
                BigDecimal oneValue = parseToBigDecimal(oneMap.get("value"));
                BigDecimal twoValue = twoFkidValueMap.get(fkid);
                if (oneValue == null) {
                    continue;
                }

                BigDecimal diff = oneValue.subtract(twoValue);
                if (diff.compareTo(BigDecimal.ZERO) <= 0) {
                    continue;
                }

                String range = getRangeByDiff(diff);
                if (range == null) {
                    continue;
                }

                RangeStatVO currentStat = rangeStatMap.get(range);
                currentStat.incrementCount();
                currentStat.addToDiffSum(diff);

            } catch (Exception e) {
                continue;
            }
        }

        // 5. 构建并返回结果（核心修改：保留两位小数）
        return buildAreaStatResult(rangeStatMap);
    }

    /**
     * 面积和体积计算（返回值保留两位小数）
     */
    @Override
    public Map<String, String> getVolumeStatistic(String tableNameOne, String tableNameTwo) {
        // 1. 校验参数和查询数据（逻辑不变）
        validateParams(tableNameOne, tableNameTwo);
        List<Map<String, Object>> mapListOne = allMapper.queryTableData(tableNameOne);
        List<Map<String, Object>> mapListTwo = allMapper.queryTableData(tableNameTwo);
        validateData(mapListOne, tableNameOne);
        validateData(mapListTwo, tableNameTwo);

        // 2. 构建表二的fkid->value映射（逻辑不变）
        Map<String, BigDecimal> twoFkidValueMap = buildFkidValueMap(mapListTwo);

        // 3. 统计有效数据（逻辑不变）
        int validCount = 0;
        BigDecimal totalDiffSum = BigDecimal.ZERO;

        for (Map<String, Object> oneMap : mapListOne) {
            try {
                String fkid = getFkid(oneMap);
                if (fkid == null || !twoFkidValueMap.containsKey(fkid)) {
                    continue;
                }
                BigDecimal oneValue = parseToBigDecimal(oneMap.get("value"));
                BigDecimal twoValue = twoFkidValueMap.get(fkid);
                if (oneValue == null) {
                    continue;
                }

                BigDecimal diff = oneValue.subtract(twoValue);
                if (diff.compareTo(BigDecimal.ZERO) <= 0) {
                    continue;
                }

                validCount++;
                totalDiffSum = totalDiffSum.add(diff);

            } catch (Exception e) {
                continue;
            }
        }

        // 4. 计算总面积和总体积（核心修改：setScale(2, ...) 保留两位小数）
        BigDecimal totalArea = BigDecimal.valueOf(validCount)
                .multiply(new BigDecimal("0.09"))
                .setScale(2, RoundingMode.HALF_UP); // 原6位改为2位，四舍五入

        BigDecimal totalVolume = totalDiffSum
                .multiply(new BigDecimal("0.09"))
                .setScale(2, RoundingMode.HALF_UP); // 原6位改为2位，四舍五入

        // 5. 封装返回结果（逻辑不变）
        Map<String, String> result = new HashMap<>(2);
        result.put("TotalArea", totalArea.toPlainString());
        result.put("totalVolume", totalVolume.toPlainString());
        return result;
    }


    // -------------------------- 内部辅助方法 --------------------------

    /**
     * 初始化区间统计容器（逻辑不变）
     */
    private Map<String, RangeStatVO> initRangeStatContainer() {
        Map<String, RangeStatVO> rangeStats = new LinkedHashMap<>();
        rangeStats.put("0--0.06", new RangeStatVO("0--0.06"));
        rangeStats.put("0.06--0.1", new RangeStatVO("0.06--0.1"));
        rangeStats.put(">0.1", new RangeStatVO(">0.1"));
        return rangeStats;
    }

    /**
     * 根据差值确定所属区间（逻辑不变）
     */
    private String getRangeByDiff(BigDecimal diff) {
        BigDecimal point06 = new BigDecimal("0.06");
        BigDecimal point1 = new BigDecimal("0.1");

        if (diff.compareTo(point06) <= 0) {
            return "0--0.06";
        } else if (diff.compareTo(point1) <= 0) {
            return "0.06--0.1";
        } else {
            return ">0.1";
        }
    }

    /**
     * 构建面积统计的返回结果（核心修改：保留两位小数）
     */
    private List<Map<String, String>> buildAreaStatResult(Map<String, RangeStatVO> rangeStatMap) {
        List<Map<String, String>> resultList = new ArrayList<>();
        BigDecimal factor = new BigDecimal("0.09");

        for (RangeStatVO stat : rangeStatMap.values()) {
            Map<String, String> rangeMap = new HashMap<>(3);
            rangeMap.put("range", stat.getRange());

            // 计算区间Area（核心修改：setScale(2, ...) 保留两位小数）
            BigDecimal area = BigDecimal.valueOf(stat.getCount())
                    .multiply(factor)
                    .setScale(2, RoundingMode.HALF_UP); // 原6位改为2位，四舍五入
            rangeMap.put("Area", area.toPlainString());

            // 计算区间Volume（核心修改：setScale(2, ...) 保留两位小数）
            BigDecimal volume = stat.getDiffSum()
                    .multiply(factor)
                    .setScale(2, RoundingMode.HALF_UP); // 原6位改为2位，四舍五入
            rangeMap.put("Volume", volume.toPlainString());

            resultList.add(rangeMap);
        }

        return resultList;
    }

    // 以下辅助方法（buildFkidValueMap、getFkid、parseToBigDecimal、validateParams、validateData）逻辑完全不变
    private Map<String, BigDecimal> buildFkidValueMap(List<Map<String, Object>> dataList) {
        Map<String, BigDecimal> fkidValueMap = new HashMap<>();
        for (Map<String, Object> dataMap : dataList) {
            try {
                String fkid = getFkid(dataMap);
                BigDecimal value = parseToBigDecimal(dataMap.get("value"));
                if (fkid != null && value != null) {
                    fkidValueMap.put(fkid, value);
                }
            } catch (Exception e) {
                continue;
            }
        }
        return fkidValueMap;
    }

    private String getFkid(Map<String, Object> dataMap) {
        Object fkidObj = dataMap.get("fkid");
        if (fkidObj == null) {
            return null;
        }

        String fkid = fkidObj.toString().trim();
        return fkid.isEmpty() ? null : fkid;
    }

    private BigDecimal parseToBigDecimal(Object value) {
        if (value == null) {
            return null;
        }
        try {
            if (value instanceof BigDecimal) {
                return (BigDecimal) value;
            } else if (value instanceof String) {
                return new BigDecimal(((String) value).trim());
            } else if (value instanceof Number) {
                return BigDecimal.valueOf(((Number) value).doubleValue());
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }

    private void validateParams(String tableNameOne, String tableNameTwo) {
        if (tableNameOne == null || tableNameTwo == null) {
            throw new IllegalArgumentException("表名参数不能为空");
        }
    }

    private void validateData(List<Map<String, Object>> dataList, String tableName) {
        if (dataList == null || dataList.isEmpty()) {
            throw new RuntimeException("表[" + tableName + "]无数据或查询失败");
        }
    }


    /**
     * 根据传入的点，进行数据查找匹配
     * 双表并行查询：修正类型不匹配问题（补充结果转换）
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, List<Map<String, String>>> getMatchIncomingPoints(MatchIncomingPointsDTO dto) {
        validateParams(dto);
        String tableOne = dto.getTableNameOne().trim();
        String tableTwo = dto.getTableNameTwo().trim();
        List<String> pointList = dto.getPointList();
        int batchSize = 5;
        CompletableFuture<List<Map<String, String>>> tableOneFuture = CompletableFuture.supplyAsync(() -> {
            List<Map<String, Object>> dbResult = querySingleTableDb(tableOne, pointList, batchSize);
            return convertDbResult(dbResult);
        }, taskExecutor);
        // 2. 表2查询：同上，补充结果转换
        CompletableFuture<List<Map<String, String>>> tableTwoFuture = CompletableFuture.supplyAsync(() -> {
            List<Map<String, Object>> dbResult = querySingleTableDb(tableTwo, pointList, batchSize);
            return convertDbResult(dbResult); // 关键修正：补充转换
        }, taskExecutor);
        // 3. 汇总结果
        Map<String, List<Map<String, String>>> finalResult = new LinkedHashMap<>();
        try {
            List<Map<String, String>> tableOneResult = tableOneFuture.get(20, TimeUnit.SECONDS);
            List<Map<String, String>> tableTwoResult = tableTwoFuture.get(20, TimeUnit.SECONDS);
            finalResult.put(dto.getTableNameOne(), tableOneResult);
            finalResult.put(dto.getTableNameTwo(), tableTwoResult);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("查询被中断", e);
        } catch (Exception e) {
            String errorMsg = e instanceof java.util.concurrent.ExecutionException
                    ? e.getCause().getMessage()
                    : e.getMessage();
            throw new RuntimeException("查询失败：" + errorMsg, e);
        }
        return finalResult;
    }

    /**
     * 单表数据库查询：返回原始Object类型结果（与Mapper返回类型一致）
     *
     * @param tableName
     * @param pointList
     * @param batchSize
     * @return
     */
    private List<Map<String, Object>> querySingleTableDb(String tableName, List<String> pointList, int batchSize) {
        List<List<String>> pointBatches = Lists.partition(pointList, batchSize);
        List<Map<String, Object>> tableDbResults = new ArrayList<>(pointBatches.size() * batchSize);
        // 串行处理批量（避免与taskExecutor的线程嵌套），减少线程竞争
        for (List<String> batch : pointBatches) {
            List<Map<String, Object>> batchResult = allMapper.queryByTableAndPoints(tableName, batch);
            if (Objects.nonNull(batchResult)) {
                tableDbResults.addAll(batchResult);
            }
        }
        return tableDbResults;
    }


    /**
     * 结果转换：将List<Map<String, Object>>转为List<Map<String, String>>
     * 当处理大数据量（例如 10 万 + 条记录）时，使用 parallelStream 可以利用多核 CPU 并行处理数据，提升转换效率。
     * @param dbResults
     * @return
     */
    private List<Map<String, String>> convertDbResult(List<Map<String, Object>> dbResults) {
        if (dbResults == null || dbResults.isEmpty()) {
            log.debug("数据库返回空结果，直接返回空列表");
            return Collections.emptyList();
        }
        // 并行流处理（仅保留必要转换，SQL已做大部分格式化）
        return dbResults.parallelStream()
                .map(dbItem -> {
                    Map<String, String> stringMap = new HashMap<>(4);
                    // 1. gid：直接转String（SQL返回的是数字类型）
                    putFieldIfValid(stringMap, "gid", dbItem.get("gid"));
                    // 2. fkid：直接转String（无特殊处理）
                    putFieldIfValid(stringMap, "fkid", dbItem.get("fkid"));
                    // 3. value：SQL已格式化，直接取String（无需Java层再处理）
                    putFieldIfValid(stringMap, "value", dbItem.get("value"));
                    // 4. geom：SQL已转WKT，直接取String（无需再处理）
                    putFieldIfValid(stringMap, "geom", dbItem.get("geom"));
                    return stringMap;
                })
                .collect(Collectors.toList());
    }

    /**
     * 工具方法：字段非空且有效时，转为String存入Map（统一处理通用字段）
     * @param targetMap 目标Map
     * @param key 字段名
     * @param value 数据库原始值
     */
    private void putFieldIfValid(Map<String, String> targetMap, String key, Object value) {
        // 过滤null和空字符串（避免存"null"或空值）
        if (value == null) {
            return;
        }
        String valueStr = value.toString().trim();
        if (!valueStr.isEmpty() && !"null".equalsIgnoreCase(valueStr)) {
            targetMap.put(key, valueStr);
        }
    }

    /**
     * 专用方法：处理value字段（保留2位小数，兼容多类型，增加异常捕获）
     * @param targetMap 目标Map
     * @param value 数据库原始value值
     */
    private void handleValueField(Map<String, String> targetMap, Object value) {
        if (value == null) {
            return;
        }

        String valueStr;
        try {
            // 按类型优先级处理（BigDecimal优先，避免Double精度丢失）
            if (value instanceof BigDecimal) {
                valueStr = ((BigDecimal) value)
                        .setScale(2, RoundingMode.HALF_UP)
                        .toString();
            } else if (value instanceof Double || value instanceof Float) {
                // 处理浮点型：避免科学计数法，保留2位小数
                valueStr = String.format("%.2f", value);
            } else if (value instanceof Number) {
                // 兼容整数类型（Integer/Long等）：转为BigDecimal后处理，确保格式统一
                valueStr = new BigDecimal(value.toString())
                        .setScale(2, RoundingMode.HALF_UP)
                        .toString();
            } else {
                // 非数值类型：尝试转为字符串后解析（如数据库存的是String类型的数字）
                BigDecimal num = new BigDecimal(value.toString().trim());
                valueStr = num.setScale(2, RoundingMode.HALF_UP).toString();
            }
            targetMap.put("value", valueStr);
        } catch (Exception e) {
            // 捕获转换异常（如非数值类型），避免整个方法失败，同时打日志便于排查
            log.warn("处理value字段失败，原始值：{}，异常信息：{}", value, e.getMessage());
            // 可选：存入原始值（或空字符串），根据业务需求决定
            targetMap.put("value", value.toString().trim());
        }
    }

//    private List<Map<String, String>> convertDbResult(List<Map<String, Object>> dbResults) {
//        if (dbResults == null || dbResults.isEmpty()) {
//            return Collections.emptyList(); // 空结果处理，避免NPE
//        }
//        return dbResults.stream()
//                .map(item -> {
//                    Map<String, String> stringMap = new HashMap<>(5);
//                    // 空值判断+类型转换：Object→String
//                    putIfNotNull(stringMap, "gid", item.get("gid"));
//                    putIfNotNull(stringMap, "fkid", item.get("fkid"));
//                    // 处理value字段（支持Double/BigDecimal，保留2位小数）
//                    if (item.get("value") != null) {
//                        String valueStr;
//                        if (item.get("value") instanceof Double) {
//                            valueStr = String.format("%.2f", (Double) item.get("value"));
//                        } else if (item.get("value") instanceof BigDecimal) {
//                            valueStr = ((BigDecimal) item.get("value")).setScale(2, RoundingMode.HALF_UP).toString();
//                        } else {
//                            valueStr = item.get("value").toString();
//                        }
//                        stringMap.put("value", valueStr);
//                    }
//                    putIfNotNull(stringMap, "geom", item.get("geom"));
//                    return stringMap;
//                })
//                .collect(Collectors.toList());
//    }



//    /**
//     * 工具方法：空值过滤+Object→String转换
//     */
//    private void putIfNotNull(Map<String, String> map, String key, Object value) {
//        if (value != null) {
//            map.put(key, value.toString()); // 核心：将任意非空Object转为String
//        }
//    }


    // ------------------------------ 参数校验------------------------------
    private void validateParams(MatchIncomingPointsDTO dto) {
        validateTableName("tableNameOne", dto.getTableNameOne());
        validateTableName("tableNameTwo", dto.getTableNameTwo());
        if (dto.getPointList() == null || dto.getPointList().isEmpty()) {
            throw new IllegalArgumentException("点列表不能为空");
        }
        for (String point : dto.getPointList()) {
            if (point == null || !point.matches("^-?\\d+\\.\\d+,[-]?\\d+\\.\\d+$")) {
                throw new IllegalArgumentException("非法点格式：" + point + "，正确格式为\"经度,纬度\"");
            }
        }
    }

    private void validateTableName(String fieldName, String tableName) {
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException(fieldName + "不能为空");
        }
        String trimmedTableName = tableName.trim();
        if (trimmedTableName.contains(";") || trimmedTableName.contains(" ")
                || trimmedTableName.matches(".*(DROP|ALTER|TRUNCATE).*")) {
            throw new IllegalArgumentException(fieldName + "非法：" + trimmedTableName);
        }
    }


    /**
     * 获取河段统计
     */
    @Override
    public RiverSumDTO getRiverDataSum() {
        return allMapper.selectSum();
    }


    /**
     * 获取统计列表
     */
    @Override
    public List<RiverInfo> selecRivertList() {
        return allMapper.selecRivertList();
    }


    /**
     * 单个点位的查询数据匹配
     *
     * @param tableName
     * @param point
     * @return
     */
    @Override
    public List<Map<String, Object>> singleTableData(String tableName, String point) {
        return allMapper.singleTableData(tableName,point);
    }






}